/***
 * * PROJECT
 * *    Logical Neighborhood Routing
 * * VERSION
 * *    $Revision: 1.5 $
 * * DATE
 * *    $Date: 2007/01/04 09:14:09 $
 * * LOG
 * *    $Log: StartSwansSim.java,v $
 * *    Revision 1.5  2007/01/04 09:14:09  lmottola
 * *    Changed constructor for AtagManager.
 * *
 * *    Revision 1.4  2006/12/20 23:05:23  lmottola
 * *    Code refactoring.
 * *
 * *    Revision 1.3  2006/12/20 22:09:46  lmottola
 * *    Changed method names.
 * *
 * *    Revision 1.2  2006/12/14 05:15:17  lmottola
 * *    Moved Estimator in atag.compiler and various cleanup.
 * *
 * *    Revision 1.1  2006/11/05 21:10:24  lmottola
 * *    Added startup script, still needing a pre-built AtagManager.
 * *
 * *    Revision 1.11  2006/11/04 02:40:00  lmottola
 * *    Implemented topology creation for SWANS.
 * *
 * *    Revision 1.10  2006/11/03 23:09:35  lmottola
 * *    Changed nodeAttributes package.
 * *
 * *    Revision 1.9  2006/11/03 23:08:17  lmottola
 * *    Traffic application beta running.
 * *
 * *
 * *   Logical Neighborhoods Routing - Java Version
 * *                                
 * *
 * *   This program is free software; you can redistribute it and/or
 * *   modify it under the terms of the GNU General Public License
 * *   as published by the Free Software Foundation; either version 2
 * *   of the License, or (at your option) any later version.
 * *
 * *   This program is distributed in the hope that it will be useful,
 * *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 * *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * *   GNU General Public License for more details.
 * *
 * *   You should have received a copy of the GNU General Public License
 * *   along with this program; if not, you may find a copy at the FSF web
 * *   site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
 * *   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * *   Boston, MA  02111-1307, USA
 ***/

package atag.apps.helloWorld;

import java.util.ArrayList;
import java.util.Vector;

import jist.runtime.JistAPI;
import jist.swans.Constants;
import jist.swans.app.AppJava;
import jist.swans.field.Field;
import jist.swans.field.Mobility;
import jist.swans.mac.MacAddress;
import jist.swans.mac.MacDumb;
import jist.swans.misc.Location;
import jist.swans.misc.Mapper;
import jist.swans.misc.Util;
import jist.swans.net.NetAddress;
import jist.swans.net.NetIp;
import jist.swans.net.PacketLoss;
import jist.swans.radio.RadioInfo;
import jist.swans.radio.RadioNoise;
import jist.swans.radio.RadioNoiseIndep;
import jist.swans.trans.TransUdp;
import atag.apps.traffic.PreBuiltAtagManager;
import atag.common.ATaGDataItemDeclaration;
import atag.common.ATaGProgram;
import atag.common.ATaGTaskDeclaration;
import atag.common.ScopedChannel;
import atag.runtime.AtagManager;
import atag.runtime.DataPool;
import atag.runtime.NodeInfo;
import atag.runtime.NodeLocation;
import atag.runtime.ln.DatagramObjectIO;
import atag.runtime.ln.LogicalNeighborhood;
import atag.runtime.ln.nodeAttributes.IntegerAttribute;
import atag.runtime.ln.nodeAttributes.NodeAttribute;
import atag.runtime.ln.swans.SimulationReferences;
import atag.runtime.platformDependent.JiSTClock;

public class StartSwansSim {

	// TODO: Need pre-built ATaG manager!!! This won't work as it stands now...
	public static void createNode(int id, Field field,
			RadioInfo.RadioInfoShared radioInfoShared, Mapper protMap,
			PacketLoss plIn, PacketLoss plOut, NodeInfo info,
			ATaGProgram atagPrg) throws NoSuchMethodException {

		// Create entities
		RadioNoise radio = new RadioNoiseIndep(id, radioInfoShared);
		MacDumb mac = new MacDumb(new MacAddress(id), radio.getRadioInfo());
		NetAddress netAddr = NetAddress.LOCAL;
		NetIp net = new NetIp(netAddr, protMap, plIn, plOut);
		TransUdp udp = new TransUdp();

		// hookup entities
		Location location = new Location.Location2D(
				info.getMyLocation().getX(), info.getMyLocation().getY());
		field.addRadio(radio.getRadioInfo(), radio.getProxy(), location);
		field.startMobility(radio.getRadioInfo().getUnique().getID());

		// radio hookup
		radio.setFieldEntity(field.getProxy());
		radio.setMacEntity(mac.getProxy());

		// mac hookup
		mac.setRadioEntity(radio.getProxy());
		byte intId = net.addInterface(mac.getProxy());
		mac.setNetEntity(net.getProxy(), intId);

		// net hookup
		net.setProtocolHandler(Constants.NET_PROTOCOL_UDP, udp.getProxy());

		// trans hookup
		udp.setNetEntity(net.getProxy());

		SimulationReferences.setNodeInfo(id, info);

		DatagramObjectIO objectIO = new DatagramObjectIO(
				LogicalNeighborhood.PORT, LogicalNeighborhood.BUFFER_SIZE,
				LogicalNeighborhood.RECEIVE_TIMEOUT);
		SimulationReferences.setObjectIO(id, objectIO);
		AppJava runObjectIO = new AppJava(DatagramObjectIO.class);
		runObjectIO.setUdpEntity(udp.getProxy());
		runObjectIO.getProxy().run(new String[] { String.valueOf(id) });
		JistAPI.sleep(1);

		LogicalNeighborhood ln = new LogicalNeighborhood(info, objectIO);
		SimulationReferences.setLN(id, ln);
		AppJava runLNTick = new AppJava(LogicalNeighborhood.class);
		runLNTick.setUdpEntity(udp.getProxy());
		runLNTick.getProxy().run(
				new String[] { "tickStart", String.valueOf(id) });
		JistAPI.sleep(1);
		AppJava runLNQueue = new AppJava(LogicalNeighborhood.class);
		runLNQueue.setUdpEntity(udp.getProxy());
		runLNQueue.getProxy().run(
				new String[] { "queueStart", String.valueOf(id) });
		JistAPI.sleep(1);

		// TODO: Need pre-built ATaG manager!!!
		AtagManager atagManager = new PreBuiltAtagManager();
		atagManager.setAtagProgram(atagPrg);
		atagManager.setNodeInfo(info);
		atagManager.setDataPool(new DataPool(ln, info, atagManager));
		atagManager.setUp();
		SimulationReferences.setAtagManager(id, atagManager);

		AppJava runAtagManager = new AppJava(AtagManager.class);
		runAtagManager.setUdpEntity(udp.getProxy());
		for (int i = 0; i < atagPrg.numTasks(); i++) {
			JistAPI.sleep(1);
			runAtagManager.getProxy().run(
					new String[] { String.valueOf(id), String.valueOf(i) });
		}
	}

	public static void main(String[] args) {
		try {

			Location.Location2D bounds = new Location.Location2D(2000, 2000);
			Mobility mobility = new Mobility.Static();

			Field field = new Field(bounds);
			field.setMobility(mobility);
			RadioInfo.RadioInfoShared radioInfoShared = RadioInfo.createShared(
					Constants.FREQUENCY_DEFAULT, Constants.BANDWIDTH_DEFAULT,
					Constants.TRANSMIT_DEFAULT, Constants.GAIN_DEFAULT, Util
							.fromDB(Constants.SENSITIVITY_DEFAULT), Util
							.fromDB(Constants.THRESHOLD_DEFAULT),
					Constants.TEMPERATURE_DEFAULT,
					Constants.TEMPERATURE_FACTOR_DEFAULT,
					Constants.AMBIENT_NOISE_DEFAULT);
			// protocol mapper
			Mapper protMap = new Mapper(Constants.NET_PROTOCOL_MAX);
			protMap.mapToNext(Constants.NET_PROTOCOL_UDP);

			// packet loss
			PacketLoss pl = new PacketLoss.Zero();

			Vector attributes;
			ATaGProgram atagPrg = returnHelloWorld();
			atagPrg.sanitize();

			NodeAttribute attrA = new IntegerAttribute("type", 0);
			attributes = new Vector();
			attributes.add(attrA);
			Vector assignedTasks = new Vector();
			assignedTasks.add(new Integer(IDConstants.T_HWREADER));
			NodeInfo typeA = new NodeInfo(0, new NodeLocation(0, 0),
					attributes, 1, assignedTasks, new JiSTClock());
			createNode(0, field, radioInfoShared, protMap, pl, pl, typeA,
					atagPrg);

			Thread.sleep(1000);
			NodeAttribute attrB = new IntegerAttribute("type", 1);
			attributes = new Vector();
			attributes.add(attrB);
			assignedTasks = new Vector();
			assignedTasks.add(new Integer(IDConstants.T_HWGENERATOR));
			NodeInfo typeB = new NodeInfo(1, new NodeLocation(400, 400),
					attributes, 1, assignedTasks, new JiSTClock());
			createNode(1, field, radioInfoShared, protMap, pl, pl, typeB,
					atagPrg);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static ATaGProgram returnHelloWorld() {

		ATaGProgram retProgram = new ATaGProgram();

		// set the tasks
		ArrayList<ATaGTaskDeclaration> tList = retProgram.getTaskList();

		ATaGTaskDeclaration newTask = new ATaGTaskDeclaration();
		newTask.setName("HelloWorldGenerator");
		int[] tempFiringRule = new int[2];
		boolean runAtInit = false;
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_PERIODIC;
		tempFiringRule[1] = 10;

		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(true);

		int[] tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_ONE_ON_NODE_ID;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 0;
		newTask.setLocation(tempTaskLocation);

		tList.add(newTask);

		// task 2
		newTask = new ATaGTaskDeclaration();
		newTask.setName("HelloWorldReader");
		tempFiringRule = new int[2];
		runAtInit = false;
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ANYDATA;
		tempFiringRule[1] = 0;

		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(runAtInit);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_ONE_ON_NODE_ID;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);

		tList.add(newTask);

		// now populate the data list
		ArrayList<ATaGDataItemDeclaration> dList = retProgram.getDataList();
		ATaGDataItemDeclaration newDataItem = new ATaGDataItemDeclaration();
		newDataItem.setName(new String("HelloWorldData"));
		dList.add(newDataItem);

		// now populate the channel list
		ArrayList<ScopedChannel> cList = retProgram.getChannelList();

		// parse this data item and insert it
		ScopedChannel newChannel = new ScopedChannel();
		// the attributes are arranged alphabetically
		newChannel.setDataName(new String("HelloWorldData"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_OUTPUT);
		newChannel.setInterest(new String("none:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("HelloWorldGenerator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		// the attributes are arranged alphabetically
		newChannel.setDataName(new String("HelloWorldData"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("all-nodes:0"));
		newChannel.setLocalFlag(false);
		newChannel.setTaskName(new String("HelloWorldReader"));
		cList.add(newChannel);

		return retProgram;
	}
}
